#include "StdAfx.h"
#include "ThirdPersonCamera.h"
#include "Input.h"
#include <iostream>

using namespace std;

ThirdPersonCamera::ThirdPersonCamera(IDirect3DDevice9 *pd3dDevice)
	: m_pd3dDevice(pd3dDevice),
	m_fDist(10.0f),
	m_fDistMin(5.0f),
	m_fDistMax(50.0f),
	m_fRotationAngleY(0.0f),
	m_pTarget(NULL)
{
	m_vecRight = D3DXVECTOR3(1.0f, 0.0f, 0.0f);
	m_vecUp = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
	m_vecLook = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
	m_vecCameraPosition = D3DXVECTOR3(0.0f, 2.0f, -25.0f);

	SetProjection();
}


ThirdPersonCamera::~ThirdPersonCamera(void)
{
}

void ThirdPersonCamera::Update()
{
	long nXDiff = Input::GetAxisRaw(Input::MouseX);
	long nYDiff = Input::GetAxisRaw(Input::MouseY);
	long nZDiff = Input::GetAxisRaw(Input::MouseZ);

	D3DXVECTOR3 vecTarget(0.0f, 0.0f, 0.0f);
	D3DXVECTOR3 vecTargetLook(0.0f, 0.0f, 0.0f);

	if (m_pTarget == NULL)
	{
		cout << "ThirdPersonCamera target not set!" << endl;
	}
	else
	{
		vecTarget = m_pTarget->Position();
		vecTargetLook = m_pTarget->Look();
	}

	D3DXMATRIX matRotation;

	if (nYDiff != 0)
	{
		D3DXMatrixRotationAxis(&matRotation, &m_vecRight, D3DXToRadian((float)nYDiff / 3.0f));
		D3DXVec3TransformCoord(&m_vecLook, &m_vecLook, &matRotation);
		D3DXVec3TransformCoord(&m_vecUp, &m_vecUp, &matRotation);
	}

	if (nXDiff != 0)
	{
		float fAngle = D3DXToRadian((float)nXDiff / 3.0f);

		D3DXMatrixRotationY(&matRotation, fAngle);
		D3DXVec3TransformCoord(&m_vecLook, &m_vecLook, &matRotation);
		D3DXVec3TransformCoord(&m_vecUp, &m_vecUp, &matRotation);

		m_fRotationAngleY += fAngle;
	}

	m_fDist += -(float)nZDiff / 100.0f;

	if (m_fDist < m_fDistMin)
	{
		m_fDist = m_fDistMin;
	}
	else if (m_fDist > m_fDistMax)
	{
		m_fDist = m_fDistMax;
	}

	D3DXMATRIX matLook;

	D3DXVec3Normalize(&m_vecLook, &m_vecLook);
	m_vecLook =  m_vecLook * m_fDist;
	D3DXMatrixTranslation(&matLook, -m_vecLook.x, -m_vecLook.y, -m_vecLook.z);
	D3DXVec3TransformCoord(&m_vecCameraPosition, &vecTarget, &matLook);

	UpdateView();

	m_pTarget->UpdateRotationY(m_fRotationAngleY);
}

//-----------------------------------------------------------------------------
// Name : updateViewMatrix()
// Desc : Builds a view matrix suitable for Direct3D.
//
// Here's what the final matrix should look like:
//
//  |   rx     ux     lx    0 |
//  |   ry     uy     ly    0 |
//  |   rz     uz     lz    0 |
//  | -(r.e) -(u.e) -(l.e)  1 |
//
// Where r = Right vector
//       u = Up vector
//       l = Look vector
//       e = Eye position in world space
//       . = Dot-product operation
//
//-----------------------------------------------------------------------------
void ThirdPersonCamera::UpdateView()
{
	D3DXVec3Normalize(&m_vecLook, &m_vecLook);         
	D3DXVec3Cross(&m_vecRight, &m_vecUp, &m_vecLook);
	D3DXVec3Normalize(&m_vecRight, &m_vecRight);  
	D3DXVec3Cross(&m_vecUp, &m_vecLook, &m_vecRight);  
	D3DXVec3Normalize(&m_vecUp, &m_vecUp);    

	m_matView._11 = m_vecRight.x;           // Rx
	m_matView._12 = m_vecUp.x;              // Ux
	m_matView._13 = m_vecLook.x;            // Lx
	m_matView._14 = 0.0f;

	m_matView._21 = m_vecRight.y;           // Ry
	m_matView._22 = m_vecUp.y;              // Uy
	m_matView._23 = m_vecLook.y;            // Ly
	m_matView._24 = 0.0f;

	m_matView._31 = m_vecRight.z;           // Rz
	m_matView._32 = m_vecUp.z;              // Uz
	m_matView._33 = m_vecLook.z;            // Lz
	m_matView._34 = 0.0f;

	m_matView._41 = -D3DXVec3Dot(&m_vecRight, &m_vecCameraPosition);    // -P*R
	m_matView._42 = -D3DXVec3Dot(&m_vecUp, &m_vecCameraPosition);       // -P*U
	m_matView._43 = -D3DXVec3Dot(&m_vecLook, &m_vecCameraPosition);     // -P*L
	m_matView._44 = 1.0f;

	m_pd3dDevice->SetTransform(D3DTS_VIEW, &m_matView);
}

void ThirdPersonCamera::SetTarget(Target *pTarget)
{
	m_pTarget = pTarget;
}

void ThirdPersonCamera::SetProjection()
{
	D3DXMatrixPerspectiveFovLH(&m_matProj, D3DXToRadian(45.0f), 640.0f / 480.0f, 0.1f, 100.0f);
	m_pd3dDevice->SetTransform(D3DTS_PROJECTION, &m_matProj);
}